#include "../../src/detail/http_base_impl.hh"
#include "../../src/http/http_call.hh"
#include "../../src/repo/src/include/root/coroutine/coroutine.h"
#include "../../src/util/os_util.hh"
#include "../../src/util/string_util.hh"
#include "../../src/util/time_util.hh"
#include "../framework/unittest.hh"
#include <iostream>

FIXTURE_BEGIN(test_http)

using namespace kratos;

CASE(TestDoRequest1) {
  http::HttpBaseImpl http(nullptr);
  http.start();
  bool done = false;
  http.do_request_async(
      "127.0.0.1", 80, "/", "GET", {}, "", 2, 0,
      [&](kratos::http::HttpCallPtr call, std::uint64_t) { done = true; });
  auto start = util::get_os_time_millionsecond();
  while (true) {
    auto now = util::get_os_time_millionsecond();
    http.update(now);
    if (now - start > 1000) {
      break;
    }
  }
  ASSERT_TRUE(done);
  http.stop();
}

CASE(TestDoRequest2) {
  http::HttpBaseImpl http(nullptr);
  http.start();
  bool done = false;
  auto retval = http.do_request_async(
      "", 80, "/", "GET", {}, "", 2, 0,
      [&](kratos::http::HttpCallPtr call, std::uint64_t) { done = true; });
  ASSERT_TRUE(!retval);
  ASSERT_TRUE(!done);
  http.stop();
}

CASE(TestDoRequest3) {
  http::HttpBaseImpl http(nullptr);
  http.start();
  http.do_request_async("127.0.0.1", 80, "/", "GET", {}, "", 2, 0, nullptr);
  auto start = util::get_os_time_millionsecond();
  while (true) {
    auto now = util::get_os_time_millionsecond();
    http.update(now);
    if (now - start > 1000) {
      break;
    }
  }
  http.stop();
}

CASE(TestDoRequestCo1) {
  http::HttpBaseImpl http(nullptr);
  http.start();
  bool done = false;
  coro_start([&](void *) {
    auto call = http.do_request_co("127.0.0.1", 80, "/", "GET", {}, "", 2);
    done = true;
  });
  auto start = util::get_os_time_millionsecond();
  while (true) {
    auto now = util::get_os_time_millionsecond();
    http.update(now);
    if (now - start > 1000) {
      break;
    }
  }
  ASSERT_TRUE(done);
  http.stop();
}

CASE(TestDoRequestCo2) {
  http::HttpBaseImpl http(nullptr);
  http.start();
  bool done = false;
  auto id = coro_start([&](void *) {
    auto call = http.do_request_co("127.0.0.1", 80, "/", "GET", {}, "", 2);
    done = true;
    coro_yield();
  });
  auto start = util::get_os_time_millionsecond();
  while (true) {
    auto now = util::get_os_time_millionsecond();
    http.update(now);
    if (now - start > 1000) {
      break;
    }
  }
  ASSERT_TRUE(done);
  coro_resume(id);
  http.stop();
}

CASE(TestDoRequestCo3) {
  http::HttpBaseImpl http(nullptr);
  http.start();
  bool done = false;
  coro_start([&](void *) {
    auto call = http.do_request_co("", 80, "/", "GET", {}, "", 2);
    done = call.expired();
  });
  auto start = util::get_os_time_millionsecond();
  while (true) {
    auto now = util::get_os_time_millionsecond();
    http.update(now);
    if (now - start > 1000) {
      break;
    }
  }
  ASSERT_TRUE(done);
  http.stop();
}

CASE(TestDoRequestCo4) {
  http::HttpBaseImpl http(nullptr);
  http.start();
  bool done = false;
  coro_start([&](void *) {
    auto call = http.do_request_co("1.2.3.4", 80, "/", "GET", {}, "", 1);
    done = call.expired();
  });
  auto start = util::get_os_time_millionsecond();
  while (true) {
    auto now = util::get_os_time_millionsecond();
    http.update(now);
    if (now - start > 1500) {
      break;
    }
  }
  ASSERT_TRUE(done);
  http.stop();
}

CASE(TestDoRequestCo5) {
  http::HttpBaseImpl http(nullptr);
  http.start();
  bool done = false;
  auto call = http.do_request_co("1.2.3.4", 80, "/", "GET", {}, "", 1);
  done = call.expired();
  ASSERT_TRUE(done);
  http.stop();
}

CASE(TestWaitRequest1) {
  http::HttpBaseImpl http(nullptr);
  http.start();
  bool done = false;
  http.wait_request_async(
      "127.0.0.1", 8000, 0,
      [&](kratos::http::HttpCallPtr request, kratos::http::HttpCallPtr response,
          std::uint64_t) -> bool {
        std::cout << request.lock()->get_full_content() << std::endl;
        response.lock()->set_content("hello world");
        response.lock()->set_status_code(200);
        done = true;
        return true;
      });
  bool equal = false;
  http.do_request_async(
      "127.0.0.1", 8000, "/", "GET", {{"test", "value"}}, "test", 1000, 0,
      [&](kratos::http::HttpCallPtr response, std::uint64_t) {
        equal = (response.lock()->get_content() == "hello world");
      });
  auto start = util::get_os_time_millionsecond();
  while (true) {
    auto now = util::get_os_time_millionsecond();
    http.update(now);
    if (now - start > 1500) {
      break;
    }
  }
  ASSERT_TRUE(done);
  ASSERT_TRUE(equal);
  http.stop();
}

CASE(TestWaitRequest2) {
  http::HttpBaseImpl http(nullptr);
  http.start();
  bool done = false;
  auto retval = http.wait_request_async(
      "", 8000, 0,
      [&](kratos::http::HttpCallPtr request, kratos::http::HttpCallPtr response,
          std::uint64_t) -> bool {
        std::cout << request.lock()->get_full_content() << std::endl;
        done = true;
        return true;
      });
  http.do_request_async("127.0.0.1", 8000, "/", "GET", {}, "", 1000, 0,
                        [](kratos::http::HttpCallPtr, std::uint64_t) {});
  ASSERT_TRUE(!retval);
  ASSERT_TRUE(!done);
  http.stop();
}

CASE(TestWaitRequest3) {
  http::HttpBaseImpl http(nullptr);
  http.start();
  bool done = false;
  http.wait_request_async(
      "127.0.0.1", 8000, 0,
      [&](kratos::http::HttpCallPtr request, kratos::http::HttpCallPtr response,
          std::uint64_t) -> bool {
        std::cout << request.lock()->get_full_content() << std::endl;
        return true;
      });
  auto retval = http.wait_request_async(
      "127.0.0.1", 8000, 0,
      [&](kratos::http::HttpCallPtr request, kratos::http::HttpCallPtr response,
          std::uint64_t) -> bool {
        std::cout << request.lock()->get_full_content() << std::endl;
        done = true;
        return true;
      });
  http.do_request_async("127.0.0.1", 8000, "/", "GET", {}, "", 1000, 0,
                        [](kratos::http::HttpCallPtr, std::uint64_t) {});
  auto start = util::get_os_time_millionsecond();
  while (true) {
    auto now = util::get_os_time_millionsecond();
    http.update(now);
    if (now - start > 1500) {
      break;
    }
  }
  ASSERT_TRUE(retval);
  ASSERT_TRUE(done);
  http.stop();
}

CASE(TestWaitRequest4) {
  http::HttpBaseImpl http(nullptr);
  http.start();
  http.wait_request_async("127.0.0.1", 8000, 0, nullptr);
  http.do_request_async("127.0.0.1", 8000, "/", "GET", {}, "", 1000, 0,
                        nullptr);
  auto start = util::get_os_time_millionsecond();
  while (true) {
    auto now = util::get_os_time_millionsecond();
    http.update(now);
    if (now - start > 1500) {
      break;
    }
  }
  http.stop();
}

CASE(TestWaitRequest5) {
  http::HttpBaseImpl http(nullptr);
  http.start();
  http.wait_request_async("127.0.0.1", 8000, 0, nullptr);
  ASSERT_TRUE(http.wait_request_async("127.0.0.1", 8000, 0, nullptr));
  http.stop();
}

CASE(TestWaitRequestCo1) {
  http::HttpBaseImpl http(nullptr);
  http.start();
  bool done = false;
  coro_start([&](void *) {
    auto call = http.wait_request_co("127.0.0.1", 8000);
    done = !call.expired();
  });
  http.do_request_async("127.0.0.1", 8000, "/a/b/c", "GET", {}, "", 1000, 0,
                        [](kratos::http::HttpCallPtr, std::uint64_t) {});
  auto start = util::get_os_time_millionsecond();
  while (true) {
    auto now = util::get_os_time_millionsecond();
    http.update(now);
    if (now - start > 1500) {
      break;
    }
  }
  ASSERT_TRUE(done);
  http.stop();
}

CASE(TestWaitRequestCo2) {
  http::HttpBaseImpl http(nullptr);
  http.start();
  bool done = false;
  coro_start([&](void *) {
    auto call = http.wait_request_co("1.2.3.4", 8000);
    done = call.expired();
  });
  auto start = util::get_os_time_millionsecond();
  while (true) {
    auto now = util::get_os_time_millionsecond();
    http.update(now);
    if (now - start > 1000) {
      break;
    }
  }
  ASSERT_TRUE(done);
  http.stop();
}

CASE(TestWaitRequestCo3) {
  http::HttpBaseImpl http(nullptr);
  http.start();
  bool done = false;
  coro_start([&](void *) {
    auto call = http.wait_request_co("", 8000);
    done = call.expired();
  });
  auto start = util::get_os_time_millionsecond();
  while (true) {
    auto now = util::get_os_time_millionsecond();
    http.update(now);
    if (now - start > 1000) {
      break;
    }
  }
  ASSERT_TRUE(done);
  http.stop();
}

CASE(TestWaitRequestCo4) {
  http::HttpBaseImpl http(nullptr);
  http.start();
  bool done = false;
  auto call = http.wait_request_co("", 8000);
  done = call.expired();
  ASSERT_TRUE(done);
  http.stop();
}

FIXTURE_END(test_http)
